import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

public class WERCalculator {

    public static void main(String[] args) {
        try {
            // 文件路径配置
            String refPath = "files/reference.txt";
            String hypPath = "files/hypothesis.txt";
            String outputPath = "files/comparison_result.txt";

            // 预处理文本（保留原始词用于显示，生成清洗词用于比较）
            List<WordPair> refWords = processText(Files.readString(Paths.get(refPath)));
            List<WordPair> hypWords = processText(Files.readString(Paths.get(hypPath)));

            // 初始化动态规划表
            int[][] dp = new int[refWords.size() + 1][hypWords.size() + 1];
            Operation[][] ops = new Operation[refWords.size() + 1][hypWords.size() + 1];

            // 填充DP表
            initializeDPTable(refWords, hypWords, dp, ops);
            fillDPTable(refWords, hypWords, dp, ops);

            // 回溯获取操作序列
            List<EditOperation> operations = traceOperations(refWords, hypWords, ops);

            // 生成并保存报告
            generateReport(refWords, operations, outputPath);

            System.out.println("分析结果已保存至: " + outputPath);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 检测文本是否包含中文字符
    private static boolean containsChineseChar(String str) {
        Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]");
        return pattern.matcher(str).find();
    }

    // 文本预处理方法
    private static List<WordPair> processText(String text) {
        List<WordPair> words = new ArrayList<>();

        // 检测是否包含中文字符
        if (containsChineseChar(text)) {
            // 使用中文分词器
            String segmentedText = TokenizerAnalyzerUtils.getAnalyzerResult(text);
            for (String token : segmentedText.split("\\s+")) {
                if (!token.isEmpty()) {
                    words.add(new WordPair(token));
                }
            }
        } else {
            // 英文按空格和标点分割
            for (String raw : text.split("[\\s\\p{Punct}]+")) {
                WordPair wp = new WordPair(raw);
                if (!wp.cleaned.isEmpty()) {
                    words.add(wp);
                }
            }
        }
        return words;
    }

    // 初始化动态规划表
    private static void initializeDPTable(List<WordPair> ref, List<WordPair> hyp,
                                          int[][] dp, Operation[][] ops) {
        // 边界条件初始化
        for (int i = 0; i <= ref.size(); i++) {
            dp[i][0] = i;
            ops[i][0] = Operation.DELETE;
        }
        for (int j = 0; j <= hyp.size(); j++) {
            dp[0][j] = j;
            ops[0][j] = Operation.INSERT;
        }
        ops[0][0] = Operation.MATCH;
    }

    // 填充DP表
    private static void fillDPTable(List<WordPair> ref, List<WordPair> hyp,
                                    int[][] dp, Operation[][] ops) {
        for (int i = 1; i <= ref.size(); i++) {
            for (int j = 1; j <= hyp.size(); j++) {
                WordPair r = ref.get(i - 1);
                WordPair h = hyp.get(j - 1);

                if (r.cleaned.equalsIgnoreCase(h.cleaned)) {
                    dp[i][j] = dp[i - 1][j - 1];
                    ops[i][j] = Operation.MATCH;
                } else {
                    int sub = dp[i - 1][j - 1] + 1;
                    int ins = dp[i][j - 1] + 1;
                    int del = dp[i - 1][j] + 1;

                    dp[i][j] = Math.min(Math.min(sub, ins), del);
                    ops[i][j] = dp[i][j] == sub ? Operation.SUBSTITUTE :
                            dp[i][j] == ins ? Operation.INSERT : Operation.DELETE;
                }
            }
        }
    }

    // 回溯操作路径
    private static List<EditOperation> traceOperations(List<WordPair> ref, List<WordPair> hyp,
                                                       Operation[][] ops) {
        List<EditOperation> operations = new ArrayList<>();
        int i = ref.size(), j = hyp.size();

        while (i > 0 || j > 0) {
            Operation op = ops[i][j];
            switch (op) {
                case MATCH:
                    operations.add(0, new EditOperation(
                            ref.get(--i).original, hyp.get(--j).original, op));
                    break;
                case SUBSTITUTE:
                    operations.add(0, new EditOperation(
                            ref.get(--i).original, hyp.get(--j).original, op));
                    break;
                case INSERT:
                    operations.add(0, new EditOperation(
                            "", hyp.get(--j).original, op));
                    break;
                case DELETE:
                    operations.add(0, new EditOperation(
                            ref.get(--i).original, "", op));
                    break;
            }
        }
        return operations;
    }

    // 生成报告
    private static void generateReport(List<WordPair> ref,
                                       List<EditOperation> operations,
                                       String outputPath) throws Exception {
        List<String> report = new ArrayList<>();
        int totalOps = operations.stream()
                .filter(op -> op.op != Operation.MATCH).toArray().length;

        report.add("=== WER 分析报告 ===");
        report.add(String.format("参考词数: %d", ref.size()));
        report.add(String.format("总编辑操作: %d", totalOps));
        report.add(String.format("词错率: %.2f%%\n", (totalOps * 100.0) / ref.size()));

        report.add("=== 详细错误 ===");
        operations.stream()
                .filter(op -> op.op != Operation.MATCH)
                .forEach(op -> report.add(op.toString()));

        try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(outputPath))) {
            for (String line : report) {
                writer.write(line);
                writer.newLine();
            }
        }
    }

    enum Operation {MATCH, SUBSTITUTE, INSERT, DELETE}

    static class EditOperation {
        String refWord;
        String hypWord;
        Operation op;

        EditOperation(String ref, String hyp, Operation op) {
            this.refWord = ref;
            this.hypWord = hyp;
            this.op = op;
        }

        @Override
        public String toString() {
            switch (op) {
                case SUBSTITUTE:
                    return String.format("[替换] %s -> %s", refWord, hypWord);
                case INSERT:
                    return String.format("[插入] -> %s", hypWord);
                case DELETE:
                    return String.format("[删除] %s ->", refWord);
                default:
                    return "";
            }
        }
    }

    // 文本预处理类
    static class WordPair {
        String original;
        String cleaned;

        WordPair(String word) {
            this.original = word;
            this.cleaned = word.replaceAll("[\\p{Punct}\\u3000-\\u303F]", ""); // 去除中英文标点
        }
    }
}